package com.ecnu.codelearn.software_analysis;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Stack;

import static com.ecnu.codelearn.software_analysis.ProgramSegmentTypeEnum.COMPLEX;
import static com.ecnu.codelearn.software_analysis.ProgramSegmentTypeEnum.CONCURRENT;

/**
 * @author caopeisheng
 */
public class ProgramSegment {
    /**
     * 当前程序语句片的字符串
     */
    private String segmentString;
    /**
     * 当前程序语句的类型
     */
    private ProgramSegmentTypeEnum programSegmentType;
    /**
     * 程序标记
     */
    private String mark;
    /**
     * 子程序语句集合（只用当前程序为复杂程序语句时，该字段才会有数据）
     */
    private List<ProgramSegment> childProgramSegments;

    private ProgramSegment() {
    }

    public static ProgramSegment build(String programInputString) throws Exception {
        ProgramSegment programSegment = new ProgramSegment();

        String markPreStr = "l";
        if (programInputString.contains("cobegin")) {
            programSegment = programSegment.constructConcurrentProgramFragment(programInputString, markPreStr);
        } else {
            programSegment = programSegment.constructProgramFragment(programInputString, markPreStr);
        }
        return programSegment;
    }

    private ProgramSegment constructConcurrentProgramFragment(String programInputString, String markPreStr) throws Exception {
        programInputString = programInputString.trim();//去除字符串头尾的空

        ProgramSegment programSegment = new ProgramSegment();
        programSegment.segmentString = programInputString;
        programSegment.mark = "m";
        //截取子程序
        int cobeginIndex = programInputString.indexOf("cobegin");
        int coendIndex = programInputString.indexOf("coend");
        String subStrProgramInput = programInputString.substring(cobeginIndex + 7, coendIndex);
        if (!subStrProgramInput.contains("||")) {
            throw new Exception("并行程序中未找到 || ");
        }
        String[] subInputPrograms = subStrProgramInput.split("\\|\\|");

        //设置子程序
        List<ProgramSegment> childSegmentList = new ArrayList<>();
        int index = 0;
        for (String subInputProgram : subInputPrograms) {
            childSegmentList.add(constructProgramFragment(subInputProgram, markPreStr + (index++) + "_" + 1));
        }
        programSegment.childProgramSegments = childSegmentList;
        programSegment.programSegmentType = CONCURRENT;
        return programSegment;
    }


    /**
     * 通过输入字符，构造imp程序树型结构，用于后续转换为一阶逻辑公式（递归）
     *
     * @param programInputString
     * @return
     * @throws Exception
     */
    private ProgramSegment constructProgramFragment(String programInputString, String markPreStr) throws Exception {
        programInputString = programInputString.trim();//去除字符串头尾的空
        List<String> splitProgramSegments = splitProgramSegment(programInputString);//分割输入的程序字符串，提取出if...endif, while...endWhile

        String markStr = markPreStr;

        ProgramSegment programSegment = new ProgramSegment();
        programSegment.segmentString = programInputString;
        programSegment.mark = markStr;
        List<ProgramSegment> childSegmentList = new ArrayList<>();

        //splitProgramSegments长度大于1时，代表是复杂语句
        if (splitProgramSegments.size() > 1) {
            int index = 1;
            for (String splitProgramSegment : splitProgramSegments) {
                childSegmentList.add(constructProgramFragment(splitProgramSegment, markStr + index++));
            }
            programSegment.programSegmentType = COMPLEX;
            programSegment.childProgramSegments = childSegmentList;
            return programSegment;
        }

        //splitProgramSegments长度等于1的情况下
        String splitProgramSegment = splitProgramSegments.get(0);

        splitProgramSegment = splitProgramSegment.trim();//去除字符串头尾的空
        if (splitProgramSegment.endsWith(";")) {//去除尾部的分号
            splitProgramSegment = splitProgramSegment.substring(0, splitProgramSegment.length() - 1);
        }

        if (splitProgramSegment.startsWith("if")) {//分支语句的情况
            //处理只有if的情况
            String[] split = programInputString.split("then");
            childSegmentList.add(constructProgramFragment(split[0].substring(2), markStr + 1));

            String[] endIfSplit = split[1].split("endIf");

            if (endIfSplit[0].contains("else")) {
                String[] splitElse = endIfSplit[0].split("else");
                childSegmentList.add(constructProgramFragment(splitElse[0], markStr + 2));
                childSegmentList.add(constructProgramFragment(splitElse[1], markStr + 3));
            } else {
                childSegmentList.add(constructProgramFragment(endIfSplit[0], markStr + 2));
            }
            programSegment.programSegmentType = ProgramSegmentTypeEnum.BRANCH;
            programSegment.childProgramSegments = childSegmentList;
        } else if (splitProgramSegment.startsWith("while")) {//循环语句的情况
            splitProgramSegment = splitProgramSegment.substring(5);
            String[] split = splitProgramSegment.split("do");
            childSegmentList.add(constructProgramFragment(split[0], markStr + 1));

            String[] endWhileSplit = split[1].split("endWhile");
            childSegmentList.add(constructProgramFragment(endWhileSplit[0], markStr + 2));

            programSegment.programSegmentType = ProgramSegmentTypeEnum.LOOP;
            programSegment.childProgramSegments = childSegmentList;
        } else {
            if (splitProgramSegment.contains(";")) {//顺序语句的情况
                int index = 1;
                for (String str : splitProgramSegment.split(";")) {
                    if (str.length() > 0) {
                        ProgramSegment segment = constructProgramFragment(str, markStr + index++);
                        childSegmentList.add(segment);
                    }
                }
                programSegment.programSegmentType = ProgramSegmentTypeEnum.SEQUENCE;
                programSegment.childProgramSegments = childSegmentList;
            } else if (programInputString.contains(":=")) {//赋值语句的情况
                programSegment.programSegmentType = ProgramSegmentTypeEnum.ASSIGNMENT;
            } else if (programInputString.contains("skip")) {
                programSegment.programSegmentType = ProgramSegmentTypeEnum.SKIP;
            } else if (programInputString.contains("wait")) {
                int index = programInputString.indexOf(")");
                ProgramSegment segment = constructProgramFragment(programInputString.substring(5, index), markStr + 1);
                childSegmentList.add(segment);
                programSegment.programSegmentType = ProgramSegmentTypeEnum.WAIT;
                programSegment.childProgramSegments = childSegmentList;
            } else {//比较语句的情况
                programSegment.programSegmentType = ProgramSegmentTypeEnum.COMPARE;
            }
        }
        return programSegment;

    }

    static class StringMatch {
        String matchStr;
        Integer index;

        public StringMatch(String matchStr, int index) {
            this.matchStr = matchStr;
            this.index = index;
        }
    }

    /**
     * 分割输入的程序字符串，提取出if...endif, while...endWhile
     *
     * @param programInputString
     * @return
     * @throws Exception
     */
    private List<String> splitProgramSegment(String programInputString) throws Exception {
        List<String> result = new ArrayList<>();

        //替换输入的字符串,方便识别
        programInputString = programInputString.replaceAll("endif", "endIf");
        programInputString = programInputString.replaceAll("endwhile", "endWhile");

        //获取"if", "endIf", "while", "endWhile"的坐标
        List<StringMatch> stringMatchList = getAllStringMatch(programInputString.trim(), "if", "endIf", "while", "endWhile");
        //讲匹配到的按照下标从大到小排序
        Collections.sort(stringMatchList, new Comparator<StringMatch>() {
            @Override
            public int compare(StringMatch o1, StringMatch o2) {
                return o1.index.compareTo(o2.index);
            }
        });

        //如果没有匹配，说明程序中只有顺序语句，直接返回
        if (stringMatchList.size() == 0) {
            result.add(programInputString);
            return result;
        }

        //定义一个栈，用于配对if...endif, while...endWhile
        Stack<StringMatch> stack = new Stack();
        int lastIndex = 0;

        for (StringMatch stringMatch : stringMatchList) {
            StringMatch pop = null;
            int matchStringLength = 0;//记录匹配的字符的长度，用于分割字符串时使用，比如endIf这里就为5
            //如果是if，while入栈
            if (stringMatch.matchStr.equals("if") || stringMatch.matchStr.equals("while")) {
                if (stack.empty() && lastIndex < stringMatch.index) {
                    result.add(programInputString.substring(lastIndex, stringMatch.index).trim());
                    lastIndex = stringMatch.index;
                }
                stack.push(stringMatch);
                continue;
            }

            if (stringMatch.matchStr.equals("endIf")) {//如果是endIf，匹配栈顶元素是否为if
                if (stack.empty()) {
                    throw new Exception("if...endIf配对失败！");
                }
                pop = stack.pop();
                matchStringLength = 5;
                if (!pop.matchStr.equals("if")) {
                    throw new Exception("if...endIf配对失败！");
                }
            } else if (stringMatch.matchStr.equals("endWhile")) {//如果是endWhile，匹配栈顶元素是否为while
                if (stack.empty()) {
                    throw new Exception("while...endWhile配对失败！");
                }
                pop = stack.pop();
                matchStringLength = 8;
                if (!pop.matchStr.equals("while")) {
                    throw new Exception("while...endWhile配对失败！");
                }
            }

            //上述步骤匹配成功，将匹配的 程序段，通过记录的下标分隔出来
            if (stack.empty() && pop != null) {
                String substring = programInputString.substring(pop.index, stringMatch.index + matchStringLength);
                result.add(substring.trim());
                lastIndex = stringMatch.index + matchStringLength;
            }
        }
        return result;
    }

    //获取字符串中，所有的匹配的字符的下标
    private List<StringMatch> getAllStringMatch(String inputStr, String... matchStrArr) {
        List<StringMatch> result = new ArrayList<>();
        for (String matchStr : matchStrArr) {
            int index = inputStr.indexOf(matchStr);//*第一个出现的索引位置
            while (index != -1) {
                result.add(new StringMatch(matchStr, index));
                index = matchStr.indexOf(matchStr, index + 1);//*从这个索引往后开始第一个出现的位置
            }
        }
        return result;
    }


    public String getSegmentString() {
        return segmentString;
    }

    public ProgramSegmentTypeEnum getProgramSegmentType() {
        return programSegmentType;
    }

    public List<ProgramSegment> getChildProgramSegments() {
        return childProgramSegments;
    }

    public String getMark() {
        return mark;
    }

    public void setMark(String mark) {
        this.mark = mark;
    }

    @Override
    public String toString() {
        return "ProgramSegment{" +
                ", segmentString='" + segmentString + '\'' +
                ", programSegmentType=" + programSegmentType +
                ", childProgramSegments=" + childProgramSegments +
                '}';
    }
}
